#include "volumerenderer.h"
#include "CUDAVolumeRenderer.h"
#include <QtGui/QHBoxLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QFileDialog>
#include <QDir>
#include <QtGui/QSlider>
#include <QPainter>

#define _USE_MATH_DEFINES
#include <math.h>

const string VolumeRenderer::DEFAULT_TF_FILENAME = "images/tf.bmp";

VolumeRenderer::VolumeRenderer(QWidget *parent, Qt::WFlags flags)
	: QWidget(parent, flags)
{
	imageLabel = new ImageLabel;
	imageLabel->setBackgroundRole(QPalette::Base);

	scrollArea = new QScrollArea;
	scrollArea->setBackgroundRole(QPalette::Dark);
	scrollArea->setWidget(imageLabel);

	imageWidthSpinBox = new QSpinBox;
	imageWidthSpinBox->setRange(1, 9999);
	imageWidthSpinBox->setValue(600);
	imageHeightSpinBox = new QSpinBox;
	imageHeightSpinBox->setRange(1, 9999);
	imageHeightSpinBox->setValue(600);

	inputFilenameComboBox = new QComboBox;
	inputFilenameButton = new QPushButton("...", this);
	inputFilenameButton->setMaximumWidth(30);
	QHBoxLayout *inputFilenameLayout = new QHBoxLayout;
	inputFilenameLayout->addWidget(inputFilenameComboBox);
	inputFilenameLayout->addWidget(inputFilenameButton);

	inputTFComboBox = new QComboBox;
	inputTFComboBox->addItem(tr(DEFAULT_TF_FILENAME.c_str()));
	inputTFButton = new QPushButton("...", this);
	inputTFButton->setMaximumWidth(30);
	QHBoxLayout *inputTFLayout = new QHBoxLayout;
	inputTFLayout->addWidget(inputTFComboBox);
	inputTFLayout->addWidget(inputTFButton);


	scaleFactorSlider = new QSlider;
	scaleFactorSlider->setFocusPolicy(Qt::StrongFocus);
    scaleFactorSlider->setTickPosition(QSlider::TicksBothSides);
    scaleFactorSlider->setTickInterval(10);
    scaleFactorSlider->setSingleStep(1);
	scaleFactorSlider->setRange(10, 100);
	scaleFactorSlider->setOrientation(Qt::Orientation::Horizontal);

	thicknessSlider = new QSlider;
	thicknessSlider->setFocusPolicy(Qt::StrongFocus);
    thicknessSlider->setTickPosition(QSlider::TicksBothSides);
    thicknessSlider->setTickInterval(100);
    thicknessSlider->setSingleStep(1);
	thicknessSlider->setRange(1, 1000);
	thicknessSlider->setValue(100);
	thicknessSlider->setOrientation(Qt::Orientation::Horizontal);
	
	directionXYDial = new QDial;
    directionXYDial->setFocusPolicy(Qt::StrongFocus);
	directionXYDial->setRange(0, 360);
    directionXYDial->setNotchesVisible(true);

	directionZSlider = new QSlider;
	directionZSlider->setFocusPolicy(Qt::StrongFocus);
    directionZSlider->setTickPosition(QSlider::TicksBothSides);
    directionZSlider->setTickInterval(10);
    directionZSlider->setSingleStep(1);
	directionZSlider->setRange(-90, 90);
	directionZSlider->setOrientation(Qt::Orientation::Vertical);

	QHBoxLayout *directionLayout = new QHBoxLayout;
	directionLayout->addWidget(directionZSlider);
	directionLayout->addWidget(directionXYDial);

	
	tfViewer = new TFViewer;
	tfViewer->setTF(DEFAULT_TF_FILENAME);
	tfViewer->repaint();

	QHBoxLayout *tfWeightsLayout = new QHBoxLayout;
	for(int i = 0;i < 10;i++)
	{
		tfWeights[i] = new QSlider;
		tfWeights[i]->setFocusPolicy(Qt::StrongFocus);
		tfWeights[i]->setTickPosition(QSlider::TicksBothSides);
		tfWeights[i]->setTickInterval(10);
		tfWeights[i]->setSingleStep(1);
		tfWeights[i]->setRange(0, 255);
		tfWeights[i]->setValue(127);
		tfWeights[i]->setOrientation(Qt::Orientation::Vertical);
		tfWeightsLayout->addWidget(tfWeights[i]);
		connect(tfWeights[i], SIGNAL(valueChanged(int)), this, SLOT(updateWeights(int)));
	}


	QFormLayout *formLayout = new QFormLayout;
	formLayout->addRow(tr("Input file:"), inputFilenameLayout);
	formLayout->addRow(tr("Scale factor:"), scaleFactorSlider);
	formLayout->addRow(tr("Thickness:"), thicknessSlider);
	formLayout->addRow(tr("Direction:"), directionLayout);
	formLayout->addRow(tr("Image width:"), imageWidthSpinBox);
	formLayout->addRow(tr("Image height:"), imageHeightSpinBox);
	formLayout->addRow(tr("TF file:"), inputTFLayout);
	formLayout->addRow(tr("TF:"), tfViewer);
	formLayout->addRow(tr("TF weights:"), tfWeightsLayout);


	visualizeButton = new QPushButton("Visualize", this);

	QVBoxLayout *menuLayout = new QVBoxLayout;
    menuLayout->addLayout(formLayout);
    menuLayout->addWidget(visualizeButton);

	QGridLayout *mainLayout = new QGridLayout;
	mainLayout->addWidget(scrollArea, 0, 0);
	mainLayout->addLayout(menuLayout, 0, 1);
	mainLayout->setColumnStretch(0, 1);
	mainLayout->setColumnMinimumWidth(1, 300);
	setLayout(mainLayout);

	// actions
	connect(visualizeButton, SIGNAL(clicked()), this, SLOT(visualize()));
	connect(inputFilenameButton, SIGNAL(clicked()), this, SLOT(selectInputFile()));
	connect(inputTFButton, SIGNAL(clicked()), this, SLOT(selectTFFile()));
	connect(imageLabel, SIGNAL(dragFinished(int, int)), this, SLOT(dragFinishedEvent(int, int)));
	connect(imageLabel, SIGNAL(wheelMoved(int)), this, SLOT(zoom(int)));
	

	setWindowTitle(tr("CUDA Volume Renderer"));
	resize(1000, 700);
}

void VolumeRenderer::selectInputFile(void)
{
	QString filePath = QFileDialog::getOpenFileName(0,
	tr("Open input file"),
	QDir::currentPath(),
	tr("DAT files (*.dat)"));

	if (!filePath.isEmpty())
	{
		if (inputFilenameComboBox->findText(filePath) == -1)
			inputFilenameComboBox->addItem(filePath);
		inputFilenameComboBox->setCurrentIndex(inputFilenameComboBox->findText(filePath));

		visualize();
	}
}

void VolumeRenderer::updateWeights(int i)
{
	int w[10];
	for(int i = 0;i < 10;i++)
	{
		w[i] = tfWeights[i]->value();
	}

	tfViewer->setWeights(w);
	tfViewer->repaint();
}

void VolumeRenderer::selectTFFile(void)
{
	QString filePath = QFileDialog::getOpenFileName(0,
	tr("Open input file"),
	QDir::currentPath(),
	tr("BMP files (*.bmp)"));

	if (!filePath.isEmpty())
	{
		if (inputTFComboBox->findText(filePath) == -1)
			inputTFComboBox->addItem(filePath);
		inputTFComboBox->setCurrentIndex(inputTFComboBox->findText(filePath));

		tfViewer->setTF(filePath.toLocal8Bit().data());
		tfViewer->repaint();
	}
}

void VolumeRenderer::dragFinishedEvent(int dx, int dy)
{
	directionXYDial->setValue(directionXYDial->value() - dx / 2);
	directionZSlider->setValue(directionZSlider->value() + dy / 2);
	
	visualize();
}

void VolumeRenderer::zoom(int amount)
{
	scaleFactorSlider->setValue(scaleFactorSlider->value() + amount / 24.f);

	visualize();
}

void VolumeRenderer::visualize(void)
{
	Settings* s = new Settings();
	string tmp(inputFilenameComboBox->currentText().toLocal8Bit().data());
	s->setInputFilename(tmp);
	tmp = inputTFComboBox->currentText().toLocal8Bit().data();
	s->setTFFilename(tmp);
	s->setScaleFactor(scaleFactorSlider->value() / 10.f);
	s->setDivisor(thicknessSlider->value() / 1000.f);

	float angle = directionXYDial->value() / 180.f * M_PI;
	float z = directionZSlider->value() / 180.f * M_PI;
	s->setDirection(sin(angle) * cos(z), sin(z), cos(angle) * cos(z));

	s->setImageWidth(imageWidthSpinBox->value());
	s->setImageHeight(imageHeightSpinBox->value());

	int w[10];
	for(int i = 0;i < 10;i++)
	{
		w[i] = tfWeights[i]->value();
	}
	s->setTFWeights(w);

	if (s->getInputFilename() != "")
	{
		CUDAVolumeRenderer renderer;
		renderer.Render(s);

		QImage img(QString(s->getOutputFilename().c_str()), 0);
		imageLabel->setPixmap(QPixmap::fromImage(img));		
		imageLabel->setAlignment(Qt::AlignCenter);
		imageLabel->adjustSize();
	}
}

VolumeRenderer::~VolumeRenderer()
{

}
